import {GraphConfigData} from "@logicflow/core";
import MyContext from "./MyContext";
import ELNode from "./type/ELNode";
import {ELType} from "./type/ELType";
import Queue from "./type/Queue";
import en from "@logicflow/extension/types/locale/en-locale/en";

export default class MyParse {
    private logicFlow: GraphConfigData;

    private context: MyContext;

    constructor(logicFlow: GraphConfigData) {
        this.logicFlow = logicFlow;
        this.context = new MyContext();
        this.context.init(logicFlow);
    }

    public parse(): ELNode {
        const startId = this.context.startId;
        const node = new ELNode();
        node.id = startId;
        this.parseThenChain(node);
        return this.context.pop();
    }

    private parseThenChain(node: ELNode, defaultData: ELNode[] = []): ELNode {
        this.context.createStackEnv(ELType.THEN);
        defaultData && defaultData.forEach(data => {
            this.context.elStack.push(data);
        })
        this.parseSingleNode(node, true);
        return this.context.quitStackEnv();
    }

    /**
     * 分析当个的then节点
     *
     * @param node    节点id
     * @param isStart 是否是then链的起点
     * @returns
     */
    private parseSingleNode(node: ELNode, isStart: boolean = false) {
        const id = node.id;
        const inNum = this.context.getSourceNum(node);
        const outNum = this.context.getEndNum(node);

        if (this.context.isEnd(id)) {
            this.context.setStackEndPoint(node);
            return null;
        }

        //这时候一定是在when分支中（起点的入度可以大于1）
        if (inNum > 1 && !isStart) {
            this.context.setStackEndPoint(node);
            return null;
        }

        //虚拟节点不展示
        if (!this.context.isStart(id)) this.context.push(node);

        //先分析特殊节点
        if (ELType.IF === node.type) {
            const next = this.parseIF(this.context.pop());
            return this.parseSingleNode(next, this.context.getSourceNum(next) === 0);
        }
        if (ELType.SWITCH === node.type) {
            const next = this.parseWhich(this.context.pop());
            return this.parseSingleNode(next, this.context.getSourceNum(next) === 0);
        }
        if (ELType.LOOP === node.type) {
            const next = this.parseLoop(this.context.pop());
            return this.parseSingleNode(next, this.context.getSourceNum(next) === 0);
        }

        //普通节点
        if (outNum === 1) {
            return this.parseSingleNode(this.context.getEndList(node)[0], false);
        }

        //否则为when节点

        const next = this.parseWhenChain(node);

        return this.parseSingleNode(next, this.context.getSourceNum(next) == 0);
    }

    /**
     * 解析When节点
     *
     * @param node when的开始节点
     * @returns when的结束节点，便于继续分析
     */
    private parseWhenChain(node: ELNode) {
        this.context.createStackEnv(ELType.WHEN);

        const end = this.parseBranch(node);

        this.context.setStackEndPoint(end);

        return this.context.quitStackEnv();
    }

    /**
     * 将各个分支依次压入栈中
     *
     * @param node
     */
    private parseBranch(node: ELNode): ELNode {
        const nodeId = node.id;
        //分支起点的出度，用于判断何时结束
        let outNum = this.context.getEndNum(node);

        const queue = new Queue<ELNode>();
        const endData: Record<string, ELNode[]> = {};

        this.context.endPoints[nodeId].forEach(startNode => {
            const startId = startNode.id;
            //将空链作为已分析完的链,取出时需要判空
            if (this.context.getSourceNum(startNode) > 1) {
                this.pushToEndData(endData, startId, null);
            }
            queue.push(startNode);
        })

        while (outNum > 0) {
            const start = queue.pop();
            if (!start) throw new Error();
            const end = this.parseThenChain(start, endData[start.id]);
            this.pushToEndData(endData, end.id, this.context.elStack.pop());

            //当入度出度匹配时，循环退出
            const endSize = endData[end.id].length;
            if (outNum === endSize) {
                queue.push(end);
                break;
            }
            if (endSize === this.context.getSourceNum(end)) {
                outNum -= endSize - 1;
                queue.push(end);
            }
        }
        const end = queue.pop();
        if (!end) throw new Error();
        endData[end.id].forEach(node1 => {
            if (!node1) return;
            this.context.push(node1);
        })

        const endSize = endData[end.id].length;
        const sourceNum = this.context.getSourceNum(end);
        this.context.setSourceNum(end, sourceNum - endSize + 1);
        return end;
    }

    private pushToEndData(endData: Record<string, ELNode[]>, endId: string, node: ELNode) {
        if (!endData[endId]) endData[endId] = [];
        endData[endId].push(node);
    }

    private parseIF(node: ELNode) {
        //if节点必然有两个分支，但是可能有undefined
        const ends = this.context.getEndList(node).filter(n => !!n);
        const outNum = ends.length;

        // 当if节点分支数为1，必须在末尾
        if (outNum == 1) {
            let child: ELNode;
            let end: ELNode;
            try {
                child = ends[0];
                end = this.context.endPoints[child.id][0];
                if (!this.context.isEnd(end.id)) throw new Error();
            } catch (err) {
                throw new Error("IF 判断节点的分支数必须为2");
            }

            node.addChild(child);
            this.context.push(node);
            return end;
        }
        if (outNum != 2) throw new Error("IF 判断节点的分支数必须为2");
        this.context.createStackEnv(ELType.IF, node.id);
        const end = this.parseBranch(node);
        this.context.setStackEndPoint(end);
        return this.context.quitStackEnv();
    }

    private parseWhich(node: ELNode): ELNode {
        const outNum = this.context.getEndNum(node);

        if (outNum <= 1) throw new Error("WHICH 分支节点的分支数必须大于1");

        this.context.createStackEnv(ELType.SWITCH, node.id);
        const end = this.parseBranch(node);
        this.context.setStackEndPoint(end);

        return this.context.quitStackEnv();
    }

    private parseLoop(node: ELNode): ELNode {
        const outNum = this.context.getEndNum(node);

        if (outNum <= 1) throw new Error("LOOP 循环节点的分支数必须大于1");
        this.context.elStack.create();
        this.context.push(node);

        const end = this.parseBranch(node);
        this.context.setStackEndPoint(end);

        return this.context.quitStackEnv();
    }
}